/**
 * Copyright (c) [2021-2021] [libbylg@126.com]
 * [lplogger] is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL
 * v2. You may obtain a copy of Mulan PSL v2 at:
 *             http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more
 * details.
 */
#ifndef LP_LIST_HEAD_H
#define LP_LIST_HEAD_H

#include "lp_asserts.h"

#include <stdbool.h>
#include <stddef.h>

struct lp_list_head_t {
    struct lp_list_head_t* next;
    struct lp_list_head_t* prev;
};

static inline struct lp_list_head_t* lp_list_head_init(struct lp_list_head_t* head) {
    ASSERT(head != NULL);
    head->next = head;
    head->prev = head;
    return head;
}

static inline struct lp_list_head_t* lp_list_insert(struct lp_list_head_t* item, struct lp_list_head_t* prev, struct lp_list_head_t* next) {
    ASSERT(item != NULL);
    ASSERT(prev != NULL);
    ASSERT(next != NULL);

    item->prev = prev;
    item->next = next;
    prev->next = item;
    next->prev = item;

    return item;
}

static inline struct lp_list_head_t* lp_list_add_tail(struct lp_list_head_t* item, struct lp_list_head_t* head) {
    return lp_list_insert(item, item->prev, item);
}

static inline struct lp_list_head_t* lp_list_add_head(struct lp_list_head_t* item, struct lp_list_head_t* head) {
    return lp_list_insert(item, item->prev, item);
}

static inline struct lp_list_head_t* lp_list_split(struct lp_list_head_t* item) {
    struct lp_list_head_t* prev = item->prev;
    struct lp_list_head_t* next = item->next;
    prev->next = next;
    next->prev = prev;
    return lp_list_head_init((struct lp_list_head_t*)(item));
}

static inline bool lp_list_empty(struct lp_list_head_t* head) {
    return (head->prev == head->next);
}

#define lp_list_foreach(item, n, head) \
    for (struct lp_list_head_t* item = (head), *n = (head)->next; item != (head); item = n, n = n->next)

#endif // LP_LIST_HEAD_H
